
Real-time web applications have historically demanded a heavy tax of boilerplate code. Developers looking to stream live event data must often wrestle with disparate technologies, manually configuring WebSocket protocols, setting up external pub/sub message brokers like Redis, and writing repetitive serialization and validation logic.
A new programming language and framework named Fitz aims to challenge this status quo. In its latest developmental showcase, the creator of Fitz has demonstrated how to transform a standard, request-response URL shortener into a fully reactive, real-time analytics dashboard. The implementation requires just 40 lines of additional code, zero external libraries, and introduces a feature rarely seen in modern backend systems: the automatic compilation of an AsyncAPI 3.0 schema directly from typed source code.
Main Facts: The Zero-Boilerplate Real-Time Stack
At the core of the Fitz philosophy is compilation-level integration. Unlike traditional web frameworks that rely on runtime libraries to handle WebSocket connections, Fitz treats real-time streaming as a native, first-class citizen.
The update introduces several breakthrough features designed to streamline developer workflows:
- The
@wsDecorator: A unified routing mechanism that handles HTTP-to-WebSocket upgrades, registers endpoints, and enforces authentication policies simultaneously. - Typed Bidirectional Connections (
WsConn<T>): By parameterizing connections with a specific data type, Fitz automates JSON serialization, deserialization, and payload validation. - Zero-Dependency Architecture: Real-time event broadcasting and connection management are handled directly by the compiled native binary. Developers do not need to install additional packages (such as Python’s
websocketsor Node’ssocket.io) or configure external pub/sub layers like Redis for standard single-node operations. - Automatic AsyncAPI 3.0 Generation: Similar to how OpenAPI documentations are generated for REST endpoints, Fitz dynamically compiles an AsyncAPI schema, allowing frontend teams to generate typed client SDKs instantly.
- Built-in Heartbeats: An out-of-the-box ping/pong mechanism designed to keep connections alive through aggressive reverse proxies and cloud load balancers.
Chronology: From Static Redirects to Live Broadcasts
To understand the impact of this update, it is necessary to trace the evolution of the application. In the previous phase of the project (Part 2), developers built a robust, production-ready URL shortener. This iteration featured standard HTTP endpoints, a PostgreSQL Object-Relational Mapper (ORM), JSON Web Token (JWT) authentication, and compiled directly into a native binary.
While functional, the application operated on a classic 1998-style request-response loop. To view click statistics, an administrator had to manually refresh the analytics page.
The transition to a real-time architecture unfolds in a systematic, three-step chronological workflow:
[User Clicks Short URL]
│
▼
[HTTP Redirect Handler Invoked] ──(Spawns Background Task)──► [Notify Dashboard Function]
│ │
▼ ▼
[User Sent to Destination] [ws.broadcast() Called]
│
▼
[All Connected Dashboards Update]
Step 1: Defining the Typed Event Model
The transition begins by defining the shape of the data that will flow over the WebSocket connection. Rather than passing raw strings or untyped JSON maps, developers define a structured ClickEvent type.
type ClickEvent
code: Str,
target_url: Str,
timestamp: Str,
Step 2: Gating the Real-Time Endpoint
The dashboard endpoint is declared using the @ws decorator. Because Fitz integrates authentication directly into its routing layer, securing the WebSocket channel uses the exact same @authenticated middleware established for the HTTP REST endpoints.
@authenticated
@ws("/dashboard")
async fn dashboard(conn: WsConn<ClickEvent>, user: User)
log.info("dashboard.connected", user_email: user.email )
loop
let msg = match conn.recv()
Ok(m) => m,
Err(_) => break, // client disconnected gracefully
// Echo loop for connection verification
conn.send(msg)
Step 3: Triggering and Broadcasting the Event
When an end-user visits a shortened link, the HTTP redirect handler executes. In addition to updating the database metrics, the server spawns an asynchronous background worker. This worker broadcasts the event across the active WebSocket pool, instantly updating any connected administrator dashboards without blocking the redirect response to the end-user.
@get("/code")
async fn redirect(db: DbConn, code: Str) -> Result<HttpResponse>
let link: Link = match Link.where(fn(l) => l.code == code).first(db).await
Ok(l) => l,
Err(_) => return Err("not found"),
// Spawn background tasks to keep the main redirect fast
spawn(increment_clicks(db, link.id))
spawn(notify_dashboard(link.code, link.target_url))
return Ok(redirect_to(link.target_url))
@background
async fn notify_dashboard(code: Str, target_url: Str)
let event = ClickEvent
code: code,
target_url: target_url,
timestamp: now_iso(),
// Broadcast payload to all clients subscribed to "/dashboard"
ws.broadcast("/dashboard", event)
Supporting Data: Code Efficiency and Protocol Maintenance
To validate the efficiency of the Fitz framework, we can compare its syntax and runtime characteristics against industry-standard backend frameworks.
The Complexity Tax: Python/FastAPI vs. Fitz
In a traditional Python stack utilizing FastAPI and Pydantic, a developer must write extensive defensive code to handle connection handshakes, manual JSON parsing, schema validation, exception catching, and disconnection cleanups.
The following side-by-side comparison highlights the structural contrast:
Standard Python/FastAPI Implementation:
# Typical FastAPI / websockets server
@app.websocket("/dashboard")
async def dashboard(websocket: WebSocket):
await websocket.accept()
while True:
try:
data = await websocket.receive_text()
# Manual validation step
msg = ClickEvent.model_validate_json(data)
except WebSocketDisconnect:
break
except ValidationError as e:
# Manual error handling and serialization
await websocket.send_text(json.dumps("error": str(e)))
continue
await websocket.send_text(msg.model_dump_json())
Fitz Native Implementation:
@ws("/dashboard")
async fn dashboard(conn: WsConn<ClickEvent>)
loop
let msg = match conn.recv()
Ok(m) => m,
Err(_) => break,
conn.send(msg)
In the Python example, the developer is forced to explicitly write the parsing, validation, and error management logic. In Fitz, the type checker evaluates the contract at compile time, reducing the runtime logic to a clean, readable loop.
Mitigating Silent Connection Drops
A common point of failure for WebSockets in production environments is connection drop-offs. Reverse proxies, load balancers, and API gateways (such as Nginx, AWS ALBs, or Cloudflare) routinely terminate idle TCP connections after 30 to 60 seconds of inactivity.
To combat this, developers usually write custom heartbeat systems. Fitz eliminates this manual step by baking heartbeats directly into the server runtime configurations:
@server(43929, ws_heartbeat_secs=30)
fn main() => 0
By setting ws_heartbeat_secs=30, the compiled native binary automatically transmits a Ping frame to every connected client every 30 seconds. If a client fails to reply with a corresponding Pong frame within the expected window, the server cleanly tears down the dead TCP connection, freeing system memory and preventing resource exhaustion.
Official Responses and Developer Sentiment
The open-source community’s response to the project, hosted on GitHub under the repository Thegreekman76/fitz, highlights a growing appreciation for unified backend toolchains. For years, web development has moved toward micro-frameworks and highly decoupled architectures. However, developers are increasingly expressing fatigue over the sheer number of configuration files, dependency updates, and serialization libraries required to maintain basic features.
When presenting the update, the creator of Fitz addressed this directly:
"The typical Python WebSocket loop has the same logic, but you have to spell it out step by step. The Fitz version encodes that logic directly into the type signature. You don’t write a single
json.dumpsorjson.loadscall. The compiler does it for you."
Early adopters of the language have praised the automatic compilation of the AsyncAPI 3.0 schema. While OpenAPI has become a standard for documenting REST APIs, AsyncAPI has lagged in adoption due to the complexity of manually authoring and maintaining YAML files for event-driven systems. By serving the schema dynamically via http://localhost:8080/asyncapi.json, Fitz allows developers to plug their live backend contracts directly into visualization tools like the AsyncAPI Studio or automated frontend client generators.
Implications: The Future of Unified Backend Design
The release of Fitz’s WebSocket implementation points to a larger, emerging trend in backend engineering: the rise of the unified, compiler-driven runtime.
Bridging the Client-Server Schema Drift
Historically, the backend and frontend of web applications have suffered from "schema drift." A backend developer changes a database column or an API response field, and unless the frontend developer manually updates their TypeScript interfaces, the application crashes at runtime.
By generating AsyncAPI 3.0 schemas automatically, Fitz creates a single source of truth. Frontend developers can run CLI code-generation tools against the compiled binary’s /asyncapi.json endpoint to automatically generate strongly-typed TypeScript WebSocket clients, ensuring that any breaking change on the backend is caught instantly in the frontend’s build pipeline.
Architectural Trade-offs and Limitations
While the Fitz approach drastically simplifies development, engineering teams must evaluate specific architectural trade-offs:
- Single-Node Memory Limits: Because the framework manages connection states and broadcasts internally without an external message broker, its out-of-the-box pub/sub mechanism is bound to a single running process. Applications scaling horizontally across multiple cloud instances will eventually require an external distribution layer to synchronize broadcasts across nodes.
- Custom Sub-Protocol Negotiation: The native implementation prioritizes standard JSON payloads. Teams requiring highly customized binary framing or niche sub-protocols may find the highly opinionated type constraints of
WsConn<T>restrictive. - Language Ecosystem Maturity: As a young language and ecosystem, Fitz does not yet possess the massive library ecosystems of established languages like Go, Rust, or Python.
Conclusion
Despite these limitations, for 90% of standard real-time use cases—such as live collaborative dashboards, chat applications, real-time telemetry, and notification feeds—Fitz presents a compelling look at the future of backend development. By consolidating HTTP routes, ORM database transactions, token-based authentication, background processing, and real-time WebSockets into a single, cohesive, compiled binary, Fitz demonstrates that building modern, reactive web systems does not have to be complex.
